/*
 * Copyright 2001-2009 OFFIS, Tammo Freese
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.easymock;

import java.io.Serializable;

import org.easymock.internal.ArgumentToString;

/**
 * A convenience implementation of {@link ArgumentsMatcher}. A subclass that
 * does not redefine any method will behave like
 * {@link MockControl#EQUALS_MATCHER}.
 * 
 * @deprecated Since EasyMock 2.0, <code>ArgumentsMatcher</code>s are only supported
 * for the legacy <code>MockControl</code>. For mock objects generated by the methods
 * on <code>EasyMock</code>, there are per-argument matchers available. For more
 * information, see the EasyMock documentation.
 */
@Deprecated
public abstract class AbstractMatcher implements ArgumentsMatcher, Serializable {

    private static final long serialVersionUID = -5463061331694985383L;

    /**
     * Checks whether an expected argument matches an actual argument; the method
     * is used by
     * {@link AbstractMatcher#matches(Object[], Object[])}. The arguments
     * provided to this method are always not <code>null</code>.
     * 
     * @param expected
     *            the expected argument.
     * @param actual
     *            the actual argument.
     * @return true if the arguments match, false otherwise.
     */
    protected boolean argumentMatches(Object expected, Object actual) {
        return expected.equals(actual);
    }

    /**
     * Converts an argument to a String, used by
     * {@link AbstractMatcher#toString(Object[])}.
     * 
     * @param argument
     *            the argument to convert to a String.
     * @return a <code>String</code> representation of the argument.
     */
    protected String argumentToString(Object argument) {
        StringBuffer result = new StringBuffer();
        ArgumentToString.appendArgument(argument, result);
        return result.toString();
    }

    /**
     * Checks whether an expected argument array matches an actual argument array.
     * This convenience implementation uses
     * <code>argumentMatches(Object, Object)</code> to check whether arguments
     * pairs match. If all the arguments match, true is returned, otherwise
     * false. In two cases, <code>argumentMatches(Object, Object)</code> is
     * not called: If both argument arrays are null, they match; if one and only
     * one is null, they do not match.
     * 
     * @param expected
     *            the expected arguments.
     * @param actual
     *            the actual arguments.
     * @return true if the arguments match, false otherwise.
     */
    public boolean matches(Object[] expected, Object[] actual) {
        if (expected == actual) {
            return true;
        }
        if (expected == null || actual == null) {
            return false;
        }
        if (expected.length != actual.length) {
            return false;
        }
        for (int i = 0; i < expected.length; i++) {
            Object expectedObject = expected[i];
            Object actualObject = actual[i];

            if (expectedObject == null && actualObject == null) {
                continue;
            }

            if (expectedObject == null && actualObject != null) {
                return false;
            }

            if (expectedObject != null && actualObject == null) {
                return false;
            }

            if (!argumentMatches(expectedObject, actualObject)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns a string representation of the matcher. This convenience
     * implementation calls {@link AbstractMatcher#argumentToString(Object)}
     * for every argument in the given array and returns the string representations
     * of the arguments separated by commas.
     * 
     * @param arguments
     *            the arguments to be used in the string representation.
     * @return a string representation of the matcher.
     */
    public String toString(Object[] arguments) {
        if (arguments == null)
            arguments = new Object[0];

        StringBuilder result = new StringBuilder();

        for (int i = 0; i < arguments.length; i++) {
            if (i > 0) {
                result.append(", ");
            }
            result.append(argumentToString(arguments[i]));
        }
        return result.toString();
    }
}
